package com.unswift.cloud.service;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.unswift.annotation.api.Api;
import com.unswift.annotation.api.ApiField;
import com.unswift.annotation.api.ApiMethod;
import com.unswift.cloud.adapter.system.attach.SystemAttachAdapter;
import com.unswift.cloud.adapter.validate.IValidateAdapter;
import com.unswift.cloud.config.AttachConfig;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachBindDataBo;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachCreateBo;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachDeleteBo;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachDownloadPathBo;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachListBo;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachModelBo;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachPageBo;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachUpdateBo;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachUploadBo;
import com.unswift.cloud.pojo.bo.system.attach.SystemAttachViewBo;
import com.unswift.cloud.pojo.dao.sql.Sql;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachDataDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachDeleteDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachInsertBatchDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachInsertBatchItemDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachInsertDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachPageDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachSearchDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachSingleDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachUpdateBatchDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachUpdateBatchItemDo;
import com.unswift.cloud.pojo.dao.system.attach.SystemAttachUpdateDo;
import com.unswift.cloud.pojo.vo.ListVo;
import com.unswift.cloud.pojo.vo.page.PageVo;
import com.unswift.cloud.pojo.vo.page.PageVo.PageRowHandler;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachBindDataVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachCreateVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachDeleteVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachDownloadPathVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachDownloadVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachListVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachModelVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachPageVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachUpdateVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachUploadVo;
import com.unswift.cloud.pojo.vo.system.attach.SystemAttachViewVo;
import com.unswift.cloud.utils.HttpUtils;
import com.unswift.exception.CoreException;
import com.unswift.utils.DateUtils;
import com.unswift.utils.EncryptionUtils;
import com.unswift.utils.ExceptionUtils;
import com.unswift.utils.FileUtils;
import com.unswift.utils.ObjectUtils;
import com.unswift.utils.StringUtils;

import jakarta.servlet.http.HttpServletResponse;

@Service
@Api(value="附件服务", author="liyunlong", date="2023-12-07", version="1.0.0")
public class SystemAttachService extends BaseService{
	
	@Autowired
	@ApiField("附件配置")
	private AttachConfig attachConfig;
	
	@Autowired
	@ApiField("附件公共服务")
	private SystemAttachAdapter systemAttachAdapter;
	
	@Autowired
	@ApiField("表单验证公共操作")
	private IValidateAdapter validateAdapter;
	
	@ApiMethod(value="查询附件分页数据", params=@ApiField("分页对象，包含分页信息及查询条件"), returns=@ApiField("包含查询数据的分页对象"))
	public PageVo<SystemAttachPageVo> findPageList(SystemAttachPageBo searchBo){
		SystemAttachPageDo search=this.convertPojo(searchBo, SystemAttachPageDo.class);//将Bo转换为Do
		search.setFirstSize((search.getCurrPage()-1)*search.getPageSize());
		systemAttachAdapter.setCreateUserSql(search, "createUserName");
		systemAttachAdapter.addWhereInList(search, "classify_", searchBo.getClassifyList());
		systemAttachAdapter.setFieldToLike(search, "name", ObjectUtils.asList("name_"));
		systemAttachAdapter.addWhereBetweenList(search, "create_time_", searchBo.getCreateStartTime(), searchBo.getCreateEndTime(), "yyyy-MM-dd HH:mm:ss");
		systemAttachAdapter.addOrderBy(search, "create_time_", Sql.ORDER_BY_DESC);
		PageVo<SystemAttachDataDo> page=systemAttachAdapter.findPageList(search);//将Do转换为Vo
		PageVo<SystemAttachPageVo> pageVo = this.convertPage(page, SystemAttachPageVo.class);
		pageVo.forEach(new PageRowHandler<SystemAttachPageVo>() {
			@Override
			public void handler(SystemAttachPageVo rowData, int index) {
				if(ObjectUtils.isNotEmpty(rowData.getFileSize())) {
					rowData.setFileSizeShow(StringUtils.showCapacity(rowData.getFileSize()));
				}
				rowData.setIsExistsName(cacheAdapter.findDictionaryValueByKey("whetherInt", getLanguage(), rowData.getIsExists()+""));
				rowData.setDataModuleName(cacheAdapter.findDictionaryValueByKey("module", getLanguage(), rowData.getDataModule()+""));
				rowData.setClassifyName(cacheAdapter.findDictionaryValueByKey("attachClassify", getLanguage(), rowData.getClassify()+""));
				super.handler(rowData, index);
			}
		});
		return pageVo;
	}
	
	@ApiMethod(value="查询附件列表数据", params=@ApiField("查询条件"), returns=@ApiField("列表数据"))
	public ListVo<SystemAttachListVo> findList(SystemAttachListBo searchBo){
		SystemAttachSearchDo search=this.convertPojo(searchBo, SystemAttachSearchDo.class);//将Bo转换为Do
		List<SystemAttachDataDo> list=systemAttachAdapter.findList(search);//将Do转换为Vo
		return new ListVo<SystemAttachListVo>(this.convertPojoList(list, SystemAttachListVo.class));
	}
	
	@ApiMethod(value="查询附件详情", params=@ApiField("详情业务实体，包含id字段"), returns=@ApiField("附件详情数据"))
	public SystemAttachViewVo view(SystemAttachViewBo viewBo){
		SystemAttachSingleDo search=this.convertPojo(viewBo, SystemAttachSingleDo.class);
		SystemAttachDataDo single=systemAttachAdapter.findSingle(search);
		return this.convertPojo(single, SystemAttachViewVo.class);//将Do转换为Vo
	}
	
	@ApiMethod(value="查询下载路径", params=@ApiField("下载路径查询条件"), returns=@ApiField("下载路径返回实体"))
	public SystemAttachDownloadPathVo getDownloadPath(SystemAttachDownloadPathBo searhcBo){
		SystemAttachSearchDo search=this.convertPojo(searhcBo, SystemAttachSearchDo.class);
		SystemAttachDataDo single=systemAttachAdapter.findFirst(search, "附件信息");
		return this.convertPojo(single, SystemAttachDownloadPathVo.class);//将Do转换为Vo
	}

	@ApiMethod(value="创建附件", params=@ApiField("创建的业务实体"), returns=@ApiField("创建结果{0：未创建，1：已创建}"))
	public SystemAttachCreateVo create(SystemAttachCreateBo createBo){
		SystemAttachInsertDo insert=this.convertPojo(createBo, SystemAttachInsertDo.class);//将Bo转换为Do
		int result=systemAttachAdapter.save(insert, true);
		return new SystemAttachCreateVo(result);
	}
	
	@ApiMethod(value="更新附件", params=@ApiField("更新的业务实体"), returns=@ApiField("更新结果{0：未创建，1：已创建}"))
	public SystemAttachUpdateVo update(SystemAttachUpdateBo updateBo){
		SystemAttachUpdateDo update=this.convertPojo(updateBo, SystemAttachUpdateDo.class);//将Bo转换为Do
		int result=systemAttachAdapter.update(update, true);
		return new SystemAttachUpdateVo(result);
	}
	
	@ApiMethod(value="删除附件", params=@ApiField("删除业务实体，包含id字段"), returns=@ApiField("删除结果{0：未创建，1：已创建}"))
	public SystemAttachDeleteVo delete(SystemAttachDeleteBo deleteBo){
		SystemAttachDeleteDo delete=this.convertPojo(deleteBo, SystemAttachDeleteDo.class);//将Bo转换为Do
		int result=systemAttachAdapter.delete(delete);
		return new SystemAttachDeleteVo(result);
	}
	
    @ApiMethod(value="上传附件", params=@ApiField("上传业务实体"), returns=@ApiField("上传生成的附件详情数据"))
    public ListVo<SystemAttachUploadVo> upload(SystemAttachUploadBo uploadBo) {
        try {
        	validateAdapter.validate("systemAttach", "upload", uploadBo, this.getUser(), systemAttachAdapter);//验证表单
        	MultipartFile[] fileList = uploadBo.getFile();
            List<SystemAttachInsertBatchItemDo> itemList=new ArrayList<SystemAttachInsertBatchItemDo>();
            SystemAttachInsertBatchItemDo item;
            String suffix, filePath;
            String today=DateUtils.format("yyyyMMdd");
            int index=1;
            for (MultipartFile file : fileList) {
            	item=new SystemAttachInsertBatchItemDo();
            	String attachName = file.getOriginalFilename();
    			if(ObjectUtils.isNotEmpty(uploadBo.getFileNameEncode()) && uploadBo.getFileNameEncode()){
    				attachName=HttpUtils.decode(attachName);
    			}
    			item.setName(attachName);
    			suffix="";
    			if(ObjectUtils.isNotEmpty(attachName) && attachName.lastIndexOf(".")!=-1) {
    				suffix=attachName.substring(attachName.lastIndexOf("."));
    				item.setType(URLConnection.guessContentTypeFromName(attachName));
            	}
    			filePath="/"+uploadBo.getClassify()+"/"+uploadBo.getModule()+"/"+today+"/"+System.nanoTime()+suffix;
            	File attachFile = new File(attachConfig.getBasePath()+filePath);
            	FileUtils.createFile(attachFile, true);
				file.transferTo(attachFile);
            	item.setFilePath(filePath);
            	item.setFileUrl(attachConfig.getAttachUrlPrefix()+EncryptionUtils.md5Hex(filePath+System.currentTimeMillis())+suffix);
            	item.setFileSize(file.getSize());
            	item.setSort(index);
            	item.setDataId(uploadBo.getDataId());
            	item.setDataModule(uploadBo.getModule());
            	item.setClassify(uploadBo.getClassify());
            	item.setIsExists((byte)1);
            	item.setSaveTime(uploadBo.getSaveTime());
            	itemList.add(item);
            	index++;
            }
            if("model".equals(uploadBo.getClassify())) {
            	List<SystemAttachDataDo> modelList = systemAttachAdapter.findModelListByModule(uploadBo.getModule());
            	if(ObjectUtils.isNotEmpty(modelList)) {
            		File source,target;
            		for (SystemAttachDataDo model : modelList) {
            			source=new File(attachConfig.getBasePath()+model.getFilePath());
            			if(attachConfig.getBackup()) {
            				target=new File(attachConfig.getBasePathBackup()+model.getFilePath());
            				FileUtils.copy(source, target, true);
            			}else {
            				FileUtils.delete(source);
            			}
						SystemAttachUpdateDo update=new SystemAttachUpdateDo();
						update.setId(model.getId());
						update.setIsExists((byte)0);
						update.setIsDelete(1);
						systemAttachAdapter.update(update, false);
					}
            	}
            }
            SystemAttachInsertBatchDo batch=new SystemAttachInsertBatchDo(itemList);
            systemAttachAdapter.saveBatch(batch, false);
            
            return new ListVo<SystemAttachUploadVo>(this.convertPojoList(itemList, SystemAttachUploadVo.class));
		} catch (CoreException e) {
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("attachment.upload.error", e, e.getMessage());
		}
    }
    
    @ApiMethod(value="附件绑定业务数据", params = @ApiField("绑定关系业务对象"), returns = @ApiField("绑定结果{0：未绑定，否则已绑定}"))
    public SystemAttachBindDataVo bindData(SystemAttachBindDataBo bindDataBo) {
    	ExceptionUtils.empty(bindDataBo.getIdList(), "field.empty", "附件id集合");
        ExceptionUtils.empty(bindDataBo.getDataId(), "field.empty", "业务数据id");
        List<SystemAttachUpdateBatchItemDo> itemList=new ArrayList<SystemAttachUpdateBatchItemDo>();
        SystemAttachUpdateBatchItemDo item;
        for (Long id : bindDataBo.getIdList()){
        	item=new SystemAttachUpdateBatchItemDo();
        	item.setId(id);
        	item.setDataId(bindDataBo.getDataId());
        	itemList.add(item);
        }
        SystemAttachUpdateBatchDo batch=new SystemAttachUpdateBatchDo(itemList);
        int result=systemAttachAdapter.updateBatch(batch, false);
        return new SystemAttachBindDataVo(result);
    }
    
    @ApiMethod(value="下载附件", params = {@ApiField("附件路径"), @ApiField("请求回调")})
    public void download(String fileUrlName, HttpServletResponse response) {
    	String fileUrl=attachConfig.getAttachUrlPrefix()+fileUrlName;
    	SystemAttachDataDo attach=systemAttachAdapter.findByFileUrl(fileUrl);
    	ExceptionUtils.empty(attach, "data.not.found", "附件信息");
    	response.setContentType(attach.getType());
    	response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encode(attach.getName()));
    	response.addHeader("Content-Length", "" + attach.getFileSize());
    	try {
    		this.download(attach.getFilePath(), response.getOutputStream());
    	} catch (CoreException e) {
    		throw e;
    	} catch (Exception e) {
    		e.printStackTrace();
    		throw ExceptionUtils.exception("attachment.download.error", e, e.getMessage());
    	}
    }
    
    @ApiMethod(value="下载附件", params = {@ApiField("附件路径"), @ApiField("请求回调")})
    public SystemAttachDownloadVo downloadByte(String fileUrlName) {
    	String fileUrl=attachConfig.getAttachUrlPrefix()+fileUrlName;
    	SystemAttachDataDo attach=systemAttachAdapter.findByFileUrl(fileUrl);
    	ExceptionUtils.empty(attach, "data.not.found", "附件信息");
    	ByteArrayOutputStream outputStream=null;
    	try {
    		outputStream=new ByteArrayOutputStream();
        	this.download(attach.getFilePath(), outputStream);
        	return new SystemAttachDownloadVo(outputStream.toByteArray());
    	} catch (CoreException e) {
    		throw e;
    	} catch (Exception e) {
			e.printStackTrace();
			throw ExceptionUtils.exception("attachment.download.error", e, e.getMessage());
		} finally {
			FileUtils.close(outputStream);
		}
    }
    
    @ApiMethod(value="下载附件", params = {@ApiField("附件路径"), @ApiField("请求回调")})
    private void download(String filePath, OutputStream stream) {
    	File file=new File(attachConfig.getBasePath()+filePath);
    	ExceptionUtils.trueException(!file.exists(), "data.not.found", "文件");
		FileUtils.copy(file, stream, false);
    }
    
    @ApiMethod(value="查询模板附件", params = {@ApiField("模板对象")}, returns = @ApiField("模板附件"))
    public SystemAttachModelVo findModelAttach(SystemAttachModelBo searchBo) {
    	ExceptionUtils.empty(searchBo.getDataModule(), "field.empty", "所属模块");
    	List<SystemAttachDataDo> modelList=systemAttachAdapter.findModelListByModule(searchBo.getDataModule());
    	if(ObjectUtils.isNotEmpty(modelList)) {
    		return this.convertPojo(modelList.get(0), SystemAttachModelVo.class);
    	}
    	return null;
    }
}
